﻿using System.Collections.Generic;
using System.Text;
using Tilver.Coder.Utility;
using Tilver.Coder.Core;

namespace Tilver.Coder.Engine
{
    internal class MOEngine<T> : EngineBase where T : IMOGenerable
    {
        /// <summary>
        /// 实体类
        /// </summary>
        public T MO { get; set; }
        /// <summary>
        /// 输出代码
        /// </summary>
        /// <returns></returns>
        public override string RenderToString()
        {
            var response = new StringBuilder();
            //生成类
            ResponseClass(response, base.Tabs);
            return response.ToString();
        }

        protected virtual void ResponseClass(StringBuilder response, int tabs)
        {
            response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, MO.Description, string.Format("{0}({1})", MO.FullName, "逻辑类")));
            response.AppendFormatLine(tabs, "public class {0} : DbManagerBase", MO.CodeName.ToCoderMOClassName());
            response.AppendTabLine(tabs, "{");
            //response.AppendLine();
            //response.AppendTabLine(tabs + 1, "#region 字段");
            //ResponseFields(response, tabs + 1);
            //response.AppendTabLine(tabs + 1, "#endregion");
            //response.AppendLine();
            //response.AppendTabLine(tabs + 1, "#region 属性");
            //ResponseProperties(response, tabs + 1);
            //response.AppendTabLine(tabs + 1, "#endregion");
            response.AppendLine();
            response.AppendTabLine(tabs + 1, "#region 构造函数");
            ResponseCtors(response, tabs + 1);
            response.AppendTabLine(tabs + 1, "#endregion");
            response.AppendLine();
            response.AppendTabLine(tabs + 1, "#region 私有方法");
            ResponsePrivate(response, tabs + 1);
            response.AppendTabLine(tabs + 1, "#endregion");
            response.AppendLine();
            response.AppendTabLine(tabs + 1, "#region Select方法集合");
            ResponseSelects(response, tabs + 1);
            response.AppendTabLine(tabs + 1, "#endregion");
            response.AppendLine();
            response.AppendTabLine(tabs + 1, "#region Insert方法集合");
            ResponseInsert(response, tabs + 1);
            response.AppendTabLine(tabs + 1, "#endregion");
            response.AppendLine();
            response.AppendTabLine(tabs + 1, "#region Update方法集合");
            ResponseUpdate(response, tabs + 1);
            response.AppendTabLine(tabs + 1, "#endregion");
            response.AppendLine();
            response.AppendTabLine(tabs + 1, "#region Delete方法集合");
            ResponseDelete(response, tabs + 1);
            response.AppendTabLine(tabs + 1, "#endregion");
            response.AppendLine();
            response.AppendTabLine(tabs + 1, "#region  自定义方法集合");
            ResponseCustomMethods(response, tabs + 1);
            response.AppendTabLine(tabs + 1, "#endregion");
            response.AppendLine();
            response.AppendTabLine(tabs, "}");
        }

        #region 字段
        protected virtual void ResponseFields(StringBuilder response, int tabs)
        {
        }
        #endregion

        #region 属性
        protected virtual void ResponseProperties(StringBuilder response, int tabs)
        {
        }
        #endregion

        #region Ctors
        /// <summary>
        /// 输出构造函数
        /// </summary>
        /// <param name="response"></param>
        /// <param name="tabs"></param>
        protected virtual void ResponseCtors(StringBuilder response, int tabs)
        {
            var moClassName = MO.CodeName.ToCoderMOClassName();
            var eoClassName = MO.CodeName.ToCoderEOClassName();

            //response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "构造函数"));
            //response.AppendFormatLine(tabs, "public {0}() : base(typeof({1}),null) {{ }}", moClassName, eoClassName);
            //response.AppendLine();

            response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "构造函数"));
            response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "routeData", "路由数据"));
            //response.AppendFormatLine(tabs, "public {0}(object routeData = null) : base(typeof({1}), routeData) {{ }}", moClassName, eoClassName);
            response.AppendFormatLine(tabs, "public {0}(object routeData = null) : base(routeData) {{ }}", moClassName);
            response.AppendLine();

            response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "构造函数"));
            response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "connectionStringName", "连接字符串名称"));
            //response.AppendFormatLine(tabs, "public {0}(string connectionStringName) : base(DbDataFactory.Create(connectionStringName)) {{ }}", moClassName);
            response.AppendFormatLine(tabs, "public {0}(string connectionStringName) : base(connectionStringName) {{ }}", moClassName);
            response.AppendLine();
        }

        #endregion

        #region Private

        protected virtual void ResponsePrivate(StringBuilder response, int tabs)
        {
            response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "数据库访问操作方法"));
            response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "sql", "SQL语句"));
            response.AppendLine(ExtensionUtil.GetCoderReturnSummary(tabs, "返回数据操作对象"));
            response.AppendTabLine(tabs, "private DbAdoBase AdoBase(string sql)");
            response.AppendTabLine(tabs, "{");
            //response.AppendTabLine(tabs + 1, "return AdoBase(sql);");
            response.AppendTabLine(tabs + 1, "return DataBase.CreateDbAdo(sql, CommandType.Text);");
            response.AppendTabLine(tabs, "}");
            response.AppendLine();
        }

        #endregion

        #region Select
        /// <summary>
        /// 输出Select方法
        /// </summary>
        /// <param name="response"></param>
        /// <param name="tabs"></param>
        protected virtual void ResponseSelects(StringBuilder response, int tabs)
        {
            //按列查询
            foreach (var column in MO.Columns)
            {
                ResponseSelectColumn(response, tabs, new List<CoderColumn> { column }, false);
            }
            response.AppendLine();
            //自定义查询
            ResponseSelectCustom(response, tabs);
            response.AppendLine();
            ////分页查询
            ResponseSelectPager(response, tabs);
            response.AppendLine();
            //ResponseSelectPageData(response, tabs);
        }
        // Select By Column & FK // return Mutile
        protected virtual void ResponseSelectColumn(StringBuilder response, int tabs, IEnumerable<CoderColumn> columns, bool isForeignKey)
        {
            string summaryName = string.Format("按{0}查询", isForeignKey ? "外键" : "字段");
            string functionName = ExtensionUtil.GetDataObjectsInfo(tabs, columns, ExtensionUtil.IndexType.FunctionName);
            string paramDesc = ExtensionUtil.GetDataObjectsInfo(tabs, columns, ExtensionUtil.IndexType.ParamSummary);
            string paramList = ExtensionUtil.GetDataObjectsInfo(tabs, columns, ExtensionUtil.IndexType.ParamList);
            string inputParam = ExtensionUtil.GetDataObjectsInfo(tabs, columns, ExtensionUtil.IndexType.InputParam);
            //string mainMethod = string.Format("public IEnumerable<{0}> SelectBy{1}({2}, int top, string sort, TransactionManager tm = null)", MO.EOName, functionName, paramList);
            string mainMethod = string.Format("public List<{0}> SelectBy{1}({2}, int top, string sort, TransactionManager tm = null)", MO.EOName, functionName, paramList);
            var boMethodInfo = MO.MOInfo.Methods.Find(w => w.Method == mainMethod);
            if (boMethodInfo == null)
            {
                boMethodInfo = new CoderMOMethodInfo();
                boMethodInfo.CommandType = MOMethodCommandTypeEnum.Select;
                boMethodInfo.MethodType = MOMethodTypeEnum.Column;
                boMethodInfo.Method = mainMethod;
                boMethodInfo.IsBuild = true;
                MO.MOInfo.Methods.Add(boMethodInfo);
            }

            if (boMethodInfo.IsBuild)
            {
                response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, summaryName));
                response.AppendLine(paramDesc);
                response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "top", "获取记录数，当top值小于或等于0时忽略top条件"));
                response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "sort", "排序表达式，如：field1 ASC,field2 DESC"));
                response.AppendLine(ExtensionUtil.GetCoderTMSummary(tabs));
                response.AppendLine(ExtensionUtil.GetCoderReturnSummary(tabs, string.Empty));
                response.AppendTabLine(tabs, mainMethod);
                response.AppendTabLine(tabs, "{");

                var select = "SELECT {0} ";
                var from = "FROM ";
                var where = "WHERE ";
                //组SELECT串
                foreach (var column in MO.Columns)
                {
                    select += DBTextStyle.GetColumnName(column.Name) + ", ";
                }
                //组FROM串
                from += DBTextStyle.GetTableFullName(MO.Owner, MO.Name) + " ";
                //组参数串
                var sbPara = new StringBuilder();
                foreach (var column in columns)
                {
                    var sqlColumnName = DBTextStyle.GetColumnName(column.Name);
                    var sqlParamName = DBTextStyle.GetParameterName(column.CodeName);
                    //组WHERE串
                    where += string.Format("{0}={1} AND ", sqlColumnName, sqlParamName);
                    sbPara.AppendFormat(tabs + 5,
                                            ".AddInParameter(\"{0}\", {1}, DbType.{2}, {3})",
                                            sqlParamName,
                                            column.CodeName.ToCoderParameterName(),
                                            column.DbType,
                                            column.Size);
                }
                response.AppendFormatLine(tabs + 1, "var sql = new StringBuilder();");
                response.AppendFormatLine(tabs + 1, "var format = new StringBuilder();");
                response.AppendFormatLine(tabs + 1, "format.Append(@\"{0} {1} {2}\");",
                    select.TrimEnd(' ', ','),
                    from.TrimEnd(' ', ','),
                    where.TrimString(string.Empty, " AND ")
                    );
                response.AppendTabLine(tabs + 1, "if (!string.IsNullOrEmpty(sort)) format.AppendFormat(\" ORDER BY {0} \", sort);");
                DBTextStyle.WriteTopSql(tabs + 1, response);
                response.AppendTabLine(tabs + 1, "return AdoBase(sql.ToString())");
                response.AppendLine(sbPara.ToString());
                response.AppendFormatLine(tabs + 5, ".ExecuteList(new {0}().GetMapper(), tm);", MO.EOName);
                response.AppendTabLine(tabs, "}");
                //response.AppendLine();
            }
        }
        /// <summary>
        /// 自定义方法
        /// </summary>
        /// <param name="response"></param>
        /// <param name="tabs"></param>
        protected virtual void ResponseSelectCustom(StringBuilder response, int tabs)
        {
            //var mainMethod = string.Format("public IEnumerable<{0}> Select(string where, int top, string sort, IEnumerable<DbParameter> paras, TransactionManager tm = null)", MO.EOName);
            var mainMethod = string.Format("public List<{0}> Select(string where, int top, string sort, IEnumerable<DbParameter> paras, TransactionManager tm = null)", MO.EOName);
            var boMethodInfo = MO.MOInfo.Methods.Find(w => w.Method == mainMethod);
            if (boMethodInfo == null)
            {
                boMethodInfo = new CoderMOMethodInfo();
                boMethodInfo.CommandType = MOMethodCommandTypeEnum.Select;
                boMethodInfo.MethodType = MOMethodTypeEnum.Other;
                boMethodInfo.Method = mainMethod;
                boMethodInfo.IsBuild = true;
                MO.MOInfo.Methods.Add(boMethodInfo);
            }
            if (boMethodInfo.IsBuild)
            {
                response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "按自定义条件查询"));
                response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "where", "自定义条件,where子句"));
                response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "top", "获取行数"));
                response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "sort", "排序表达式"));
                response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "paras", "where子句中定义的参数集合"));
                response.AppendLine(ExtensionUtil.GetCoderTMSummary(tabs));
                response.AppendLine(ExtensionUtil.GetCoderReturnSummary(tabs, string.Empty));
                response.AppendTabLine(tabs, mainMethod);
                response.AppendTabLine(tabs, "{");
                var select = "SELECT {0} ";
                var from = "FROM ";
                foreach (var column in MO.Columns)
                {
                    select += DBTextStyle.GetColumnName(column.Name) + ", ";
                }
                from += DBTextStyle.GetTableFullName(MO.Owner, MO.Name) + " ";
                response.AppendTabLine(tabs + 1, "var sql = new StringBuilder();");
                response.AppendTabLine(tabs + 1, "var format = new StringBuilder();");
                response.AppendFormatLine(tabs + 1, "format.Append(@\"{0} {1} \");", select.TrimEnd(' ', ','), from.TrimEnd(' ', ','));
                response.AppendTabLine(tabs + 1, "if (!string.IsNullOrEmpty(where)) format.AppendFormat(\" WHERE {0} \", where);");
                response.AppendTabLine(tabs + 1, "if (!string.IsNullOrEmpty(sort)) format.AppendFormat(\" ORDER BY {0} \", sort);");
                DBTextStyle.WriteTopSql(tabs + 1, response);
                response.AppendTabLine(tabs + 1, "return AdoBase(sql.ToString())");
                response.AppendTabLine(tabs + 5, ".AddParameters(paras)");
                response.AppendFormatLine(tabs + 5, ".ExecuteList(new {0}().GetMapper(), tm);", MO.EOName);
                response.AppendTabLine(tabs, "}");
                //response.AppendLine();
            }
        }
        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="response"></param>
        /// <param name="tabs"></param>
        protected void ResponseSelectPager(StringBuilder response, int tabs)
        {
            //string mainMethod = string.Format("public IEnumerable<{0}> SelectPager(string where, string sort, IList<DbParameter> paras, long pageSize, long pageIndex, ref long recordCount)", MO.EOName);
            string mainMethod = string.Format("public List<{0}> SelectPager(string where, string sort, IList<DbParameter> paras, long pageSize, long pageIndex, ref long recordCount)", MO.EOName);
            var boMethodInfo = MO.MOInfo.Methods.Find(w => w.Method == mainMethod);
            if (boMethodInfo == null)
            {
                boMethodInfo = new CoderMOMethodInfo();

                boMethodInfo.CommandType = MOMethodCommandTypeEnum.Select;
                boMethodInfo.MethodType = MOMethodTypeEnum.Other;
                boMethodInfo.Method = mainMethod;
                boMethodInfo.IsBuild = true;
                MO.MOInfo.Methods.Add(boMethodInfo);
            }

            if (boMethodInfo.IsBuild)
            {
                response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "分页查询"));
                response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "where", "条件表达式"));
                response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "sort", "排序表达式"));
                response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "paras", "传入参数"));
                response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "pageSize", "页大小"));
                response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "pageIndex", "页码"));
                response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "recordCount", "总记录数，由于计算总记录数影响数据库性能，只有小于或等于0的情况下才返回总记录数"));
                response.AppendLine(ExtensionUtil.GetCoderReturnSummary(tabs, "分页数据"));
                response.AppendTabLine(tabs, mainMethod);
                response.AppendTabLine(tabs, "{");
                var select = "SELECT ";
                var from = "FROM ";
                foreach (var column in MO.Columns)
                {
                    select += DBTextStyle.GetColumnName(column.Name) + ", ";
                }
                from += DBTextStyle.GetTableFullName(MO.Owner, MO.Name) + " ";
                response.AppendTabLine(tabs + 1, "var sql = new StringBuilder();");
                response.AppendFormatLine(tabs + 1, "sql.AppendFormat(@\"{0} {1}\");",
                    select.TrimEnd(' ', ','),
                    from.TrimEnd(' ', ','));
                response.AppendTabLine(tabs + 1, "if (!string.IsNullOrEmpty(where)) sql.AppendFormat(\" WHERE {0} \", where);");
                response.AppendTabLine(tabs + 1, "if (!string.IsNullOrEmpty(sort)) sql.AppendFormat(\" ORDER BY {0} \", sort);");

                if (MO.HasPrimaryKey)
                {
                    var primaryKey = MO.HasPrimaryKey ? string.Join(", ", MO.PrimaryKey.MemberColumnNames) : string.Empty;
                    //response.AppendFormatLine(tabs + 1, "var pager = new DbPager(sql.ToString(), pageSize, \"{0}\", this.DataBase);", primaryKey);
                    response.AppendFormatLine(tabs + 1, "var pager = this.DataBase.CreatePager(sql.ToString(), pageSize, \"{0}\");", primaryKey);
                }
                else
                {
                    //response.AppendTabLine(tabs + 1, "var pager = new DbPager(sql.ToString(), pageSize, this.DataBase);");
                    response.AppendTabLine(tabs + 1, "var pager = this.DataBase.CreatePager(sql.ToString(), pageSize);");
                }
                response.AppendTabLine(tabs + 1, "pager.AddParameters(paras);");
                response.AppendTabLine(tabs + 1, "if (recordCount <= 0)");
                response.AppendTabLine(tabs + 1, "{");
                response.AppendTabLine(tabs + 2, "recordCount = pager.GetRecordCount();");
                response.AppendTabLine(tabs + 1, "}");
                response.AppendFormatLine(tabs + 1, "return pager.GetPageData(pageIndex).MapToList(new {0}().GetMapper());", MO.EOName);
                response.AppendTabLine(tabs, "}");
            }
        }
        
        #endregion

        #region Insert
        protected virtual void ResponseInsert(StringBuilder response, int tabs)
        {
        }
        #endregion

        #region Update
        protected virtual void ResponseUpdate(StringBuilder response, int tabs)
        {
        }
        #endregion

        #region Delete
        /// <summary>
        /// 删除方法
        /// </summary>
        /// <param name="response"></param>
        /// <param name="tabs"></param>
        protected virtual void ResponseDelete(StringBuilder response, int tabs)
        {
        }

        #endregion

        #region Custom
        /// <summary>
        /// 自定义方法
        /// </summary>
        /// <param name="response"></param>
        /// <param name="tabs"></param>
        protected virtual void ResponseCustomMethods(StringBuilder response, int tabs)
        {
            //var customMethodEngine = new CustomMethodEngine();
            //foreach (AbstractCustomMethod customMethod in MO.CustomMethods)
            //{
            //    customMethodEngine.Response(response, tabs, customMethod);
            //    response.AppendLine();
            //}
        }
        #endregion
    }
}
